package com.by.rpc.protocol;

import com.by.rpc.model.RpcRequest;
import com.by.rpc.model.RpcResponse;
import com.by.rpc.serializer.Serializer;
import com.by.rpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;

import java.io.IOException;
import java.rmi.RemoteException;

/**
 * 协议消息解码器
 *
 * @author lzh
 */
public class ProtocolMessageDecoder {

    /**
     * 解码器
     *
     * @param buffer 编码后的数据
     * @return 解码后的数据
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException {
        // 校验魔数
        byte magic = buffer.getByte(0);
        if (magic != ProtocolConstant.PROTOCOL_MAGIC) {
            throw new RuntimeException("消息 Magic 非法");
        }

        // 读取消息字段
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        header.setVersion(buffer.getByte(1));
        header.setSerializer(buffer.getByte(2));
        header.setType(buffer.getByte(3));
        header.setStatus(buffer.getByte(4));
        header.setRequestId(buffer.getLong(5));
        header.setBodyLength(buffer.getInt(13));

        // 解决粘包问题，只读取指定长度的字节数
        byte[] bytes = buffer.getBytes(17, 17 + header.getBodyLength());

        // 获取序列化器
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if (serializerEnum == null) {
            throw new RuntimeException("序列化协议不存在");
        }
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getValue());

        // 获取消息类型
        ProtocolMessageTypeEnum typeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if (typeEnum == null) {
            throw new RuntimeException("消息类型不存在");
        }

        // 根据消息类型解码成不同的响应体
        switch (typeEnum) {
            case REQUEST:
                RpcRequest rpcRequest = serializer.deserialize(bytes, RpcRequest.class);
                return new ProtocolMessage<>(header, rpcRequest);
            case RESPONSE:
                RpcResponse rpcResponse = serializer.deserialize(bytes, RpcResponse.class);
                return new ProtocolMessage<>(header, rpcResponse);
            default:
                throw new RemoteException("暂不支持该协议类型");
        }
    }
}
